package com.joe.xl.demo.other.reference;

import java.lang.ref.*;

/****
 * 关于JVM怎么知道引用在不在，这就涉及到了JVM的可达性分析算法了
 * JVM的可达性分析算法的简单思路就是通过一系列GC Roots作为出发点，向下搜索，搜索所走过的路径称为引用链，
 * 当一个对象到GC Roots没有任何引用链，即表明从GC Roots到这个对象不可达时，证明此对象不可用，可被回收
 */
public class ReferenceDemo {
    public static void main(String[] args) {
        // 软引用关联的对象，在内存不够的情况下，会把这些软引用关联的对象列入垃圾回收范围中，
        // 然后进行回收，也就是说软引用并非是完全安全的，在内存不够的情况下是会被垃圾回收器回收掉的。
        /*SoftReference<String> stringSoftReference = new SoftReference<String>(new String("joexl"));*/


        // 弱引用比软引用更弱，被弱引用关联的对象只能存活到发生下一次垃圾回收之前，
        // 也就是说当发生GC时，无论当前内存是否足够，都会被回收掉。
        /*WeakReference<String> weakReference = new WeakReference<String>(new String("hello joe"));
        System.out.println(weakReference.get());
        System.gc();
        System.out.println(weakReference.get());*/


        /***
         * 虚引用和上面不同的地方在于，一个对象是否有虚引用的存在，完全不会对其生存时间构成如何影响，
         * 并且也无法通过虚引用来获取一个对象的实例，也就是说跟没有引用与之关联一样，在任何时候都可能被垃圾回收器回收。
         * 无法通过虚引用来获取一个对象的实例，并且在回收后会被放入队列中。
         * 作用就是能在这个对象被收集器回收时收到一个系统通知，实现追踪垃圾收集器的回收动作，比如在对象被回收的时候，会调用该对象的finalize方法。
         * -------------
         * ReferenceQueue 引用其实也可以归纳为引用中的一员，可以和上述三种引用类型组合使用【软引用、弱引用、虚引用】
         * 在创建Reference时，手动将Queue注册到Reference中，而当该Reference所引用的对象被垃圾收集器回收时，
         * JVM会将该Reference放到该队列中，而我们便可以对该队列做些其他业务，相当于一种通知机制。
         */
        ReferenceQueue<Object> referenceQueue = new ReferenceQueue<>();
        PhantomReference<String> phantomReference = new PhantomReference<String>(new String("hello phantom"), referenceQueue);
        WeakReference<String> weakReference = new WeakReference<String>(new String("hello joe"), referenceQueue);
        System.out.println(phantomReference.get()); // null
        System.out.println(weakReference.get()); // hello joe
        System.out.println(phantomReference); //
        System.out.println(weakReference); //
        System.out.println("--------------------");

        System.gc();
        System.out.println(phantomReference.get()); // null
        System.out.println(weakReference.get()); // null
        System.out.println("--------------------");

        Reference reference;
        while ((reference = referenceQueue.poll()) != null){
            /*if(reference == phantomReference){
                System.out.println("phantom has already gc...");
            }*/
            System.out.println(reference);
        }

    }
}
